import random

from django import forms
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from web import models
from projectmanager import settings
from utils.tencent import sms
from django_redis import get_redis_connection
from utils.encrypy import md5
from web.forms.bootstrapbase import BootStrapForm




class RegisterForm(BootStrapForm, forms.ModelForm):
    password = forms.CharField(label='密码',
                               min_length=8,
                               max_length=64,
                               error_messages={
                                   'min_length': "重复密码长度不能小于8个字符",
                                   'max_length': "重复密码长度不能大于64个字符"
                               },
                               widget=forms.PasswordInput())

    confirm_password = forms.CharField(label='重复密码',
                                       min_length=8,
                                       max_length=64,
                                       error_messages={
                                           'min_length': "重复密码长度不能小于8个字符",
                                           'max_length': "重复密码长度不能大于64个字符"
                                       },
                                       widget=forms.PasswordInput())

    mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ])
    code = forms.CharField(label="验证码", widget=forms.TextInput())

    # 如果不重写init方法，想要给每个字段增加样式或者其他属性，拿code这个field举例：
    # code = forms.CharField(label='验证码', widget=forms.TextInput(attrs='', placehold=''))

    class Meta:
        model = models.UserInfo
        # fields = "__all__"  # 先按照models里面属性的顺序从上到下排列表单 如果想改变表单的顺序使用可以使用列表传递
        fields = ['username', 'email', 'password', 'confirm_password', 'mobile_phone', 'code']

    def clean_username(self):
        username = self.cleaned_data.get('username')
        exists = models.UserInfo.objects.filter(username=username).exists()
        if exists:
            raise ValidationError('用户名已存在')
            # self.add_error('username','用户名已存在')
        return username

    def clean_email(self):
        email = self.cleaned_data.get('email')
        exists = models.UserInfo.objects.filter(email=email).exists()
        if exists:
            raise ValidationError('邮箱已存在')
        return email

    def clean_password(self):
        pwd = self.cleaned_data['password']
        # 加密 & 返回
        return md5(pwd)

    def clean_confirm_password(self):
        pwd = self.cleaned_data.get('password')

        confirm_pwd = md5(self.cleaned_data.get('confirm_password'))

        if pwd != confirm_pwd:
            raise ValidationError('两次密码不一致')

        return confirm_pwd

    def clean_mobile_phone(self):
        mobile_phone = self.cleaned_data.get('mobile_phone')
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if exists:
            raise ValidationError('手机号已注册')
        return mobile_phone

    def clean_code(self):
        code = self.cleaned_data.get('code')

        # mobile_phone = self.cleaned_data['mobile_phone']

        mobile_phone = self.cleaned_data.get('mobile_phone')
        if not mobile_phone:
            return code

        conn = get_redis_connection()
        redis_code = conn.get(mobile_phone)
        if not redis_code:
            raise ValidationError('验证码失效或未发送，请重新发送')

        redis_str_code = redis_code.decode('utf-8')

        if code.strip() != redis_str_code:
            raise ValidationError('验证码错误，请重新输入')

        return code


class SendSmsForm(forms.Form):
    mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ])

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_mobile_phone(self):
        """ 验证手机号的钩子 """
        mobile_phone = self.cleaned_data['mobile_phone']

        # 判断短信模板是否有问题
        tpl = self.request.GET.get('tpl')
        template_id = settings.TENCENT_SMS_APP_TPL.get(tpl)
        if not template_id:
            raise ValidationError('短信模板错误')

        # 校验数据库中是否已有手机号
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if tpl == 'register':
            if exists:
                raise ValidationError('手机号已存在')
        elif tpl == 'login':
            if not exists:
                raise ValidationError('手机号不存在，不能使用验证码登录')

        code = random.randrange(1000, 9999)

        # 发送短信
        sms_result = sms.send_message_tool(receivers=[mobile_phone, ], tpl=template_id, code=str(code))
        if not sms_result['status']:
            raise ValidationError(f'短信发送失败, {sms_result["message"]}')

        # 验证码写入redis中
        conn = get_redis_connection('default')
        conn.set(mobile_phone, str(code), ex=180)

        return mobile_phone


class SmsLoginForm(BootStrapForm, forms.Form):
    mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ])
    code = forms.CharField(label="验证码", widget=forms.TextInput())

    def clean_mobile_phone(self):
        mobile_phone = self.cleaned_data['mobile_phone']
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        # user_object = models.UserInfo.objects.filter(mobile_phone=mobile_phone).first()
        if not exists:
            raise ValidationError('手机号不存在')

        return mobile_phone

    def clean_code(self):
        code = self.cleaned_data['code']
        mobile_phone = self.cleaned_data.get('mobile_phone')

        # 手机号不存在，则验证码无需再校验
        if not mobile_phone:
            return code

        conn = get_redis_connection()
        redis_code = conn.get(mobile_phone)  # 根据手机号去获取验证码
        if not redis_code:
            raise ValidationError('验证码失效或未发送，请重新发送')

        redis_str_code = redis_code.decode('utf-8')

        if code.strip() != redis_str_code:
            raise ValidationError('验证码错误，请重新输入')

        return code


class LoginForm(BootStrapForm, forms.Form):
    username = forms.CharField(label='用户名')
    password = forms.CharField(label='密码', widget=forms.PasswordInput(render_value=True))
    code = forms.CharField(label='图片验证码')

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_password(self):
        pwd = self.cleaned_data.get('password')
        return md5(pwd)

    def clean_code(self):
        code = self.cleaned_data.get('code')
        if not code:
            raise ValidationError('验证码未输入')
        image_code = self.request.session.get('image_code')
        if not image_code:
            raise ValidationError('验证码无效或已过期')
        if str(code).strip().upper() != str(image_code).strip().upper():
            raise ValidationError('验证码错误')
        return code



